"""
Fish Audio TTS语音合成模块
提供更自然的语音合成效果
官网: https://fish.audio
"""

import os
import time
import wave
import uuid
import requests
from typing import List, Optional, Tuple
from pathlib import Path
from io import BytesIO

import numpy as np
from pydub import AudioSegment

from ..core.models import LipSyncData
from ..utils.logger import get_logger
from ..utils.temp_file_manager import get_temp_file_manager


class FishAudioTTS:
    """Fish Audio TTS语音合成引擎"""

    def __init__(
        self,
        api_key: str,
        reference_id: Optional[str] = None,
        api_url: str = "https://api.fish.audio/v1/tts",
        format: str = "wav",
        chunk_length: int = 200,
        max_new_tokens: int = 1024,
        timeout: int = 30
    ):
        """
        初始化Fish Audio TTS引擎
        
        Args:
            api_key: Fish Audio API密钥
            reference_id: 参考音色ID(可选,使用预配置的音色)
            api_url: API接口地址
            format: 音频格式(wav/mp3/pcm)
            chunk_length: 合成块长度(100-300)
            max_new_tokens: 最大生成token数
            timeout: 请求超时时间(秒)
        """
        self.api_key = api_key
        self.reference_id = reference_id
        self.api_url = api_url
        self.format = format
        self.chunk_length = chunk_length
        self.max_new_tokens = max_new_tokens
        self.timeout = timeout

        self.logger = get_logger()
        self.current_audio: Optional[AudioSegment] = None
        self.current_lipsync_data: List[LipSyncData] = []
        
        # 使用统一的临时文件管理器
        self.temp_manager = get_temp_file_manager()
        self.temp_dir = self.temp_manager.get_temp_dir('audio')
        self.logger.info(f"✓ Fish Audio TTS引擎初始化完成")
        self.logger.debug(f"   API地址: {self.api_url}")
        self.logger.debug(f"   音频格式: {self.format}")

    def synthesize(self, text: str) -> Tuple[Optional[AudioSegment], List[LipSyncData]]:
        """
        合成语音
        
        Args:
            text: 要合成的文本
            
        Returns:
            (音频对象, 口型同步数据列表)
        """
        try:
            self.logger.debug(f"正在使用Fish Audio合成语音: {text[:50]}...")

            # 构建请求数据
            request_data = {
                "text": text,
                "format": self.format,
                "chunk_length": self.chunk_length,
                "max_new_tokens": self.max_new_tokens,
                "streaming": False  # 非流式输出
            }
            
            # 如果有参考音色ID,添加到请求中
            if self.reference_id:
                request_data["reference_id"] = self.reference_id

            # 设置请求头
            headers = {
                "Authorization": f"Bearer {self.api_key}",
                "Content-Type": "application/json"
            }

            # 发送请求
            response = requests.post(
                self.api_url,
                json=request_data,
                headers=headers,
                timeout=self.timeout
            )

            # 检查响应状态
            if response.status_code != 200:
                error_msg = f"API请求失败: HTTP {response.status_code}"
                try:
                    error_detail = response.json()
                    error_msg += f" - {error_detail}"
                except:
                    error_msg += f" - {response.text[:200]}"
                self.logger.error(error_msg)
                return None, []

            # 保存音频到项目临时目录
            temp_filename = f"fish_tts_{uuid.uuid4().hex[:8]}.{self.format}"
            temp_file_path = self.temp_dir / temp_filename
            
            # 跟踪临时文件
            self.temp_manager.track_file(temp_file_path)
            
            # 写入音频数据
            with open(temp_file_path, 'wb') as f:
                f.write(response.content)

            # 加载音频
            audio = AudioSegment.from_file(str(temp_file_path), format=self.format)
            self.current_audio = audio

            # 如果是WAV格式,提取口型同步数据
            if self.format == 'wav':
                lipsync_data = self._extract_lipsync_data(str(temp_file_path))
            else:
                # 对于非WAV格式,转换为WAV后提取
                wav_temp_path = self.temp_dir / f"fish_tts_{uuid.uuid4().hex[:8]}.wav"
                audio.export(str(wav_temp_path), format='wav')
                self.temp_manager.track_file(wav_temp_path)
                lipsync_data = self._extract_lipsync_data(str(wav_temp_path))
                self.temp_manager.cleanup_file(wav_temp_path)
            
            self.current_lipsync_data = lipsync_data

            # 删除临时文件
            try:
                self.temp_manager.cleanup_file(temp_file_path)
            except Exception as e:
                self.logger.warning(f"清理临时文件失败: {e}")

            self.logger.info(f"✓ Fish Audio语音合成成功,时长: {len(audio)/1000:.2f}秒")

            return audio, lipsync_data

        except requests.exceptions.Timeout:
            self.logger.error(f"Fish Audio API请求超时 (>{self.timeout}秒)")
            return None, []
        except requests.exceptions.RequestException as e:
            self.logger.error(f"Fish Audio API请求异常: {e}")
            return None, []
        except Exception as e:
            self.logger.error(f"Fish Audio语音合成异常: {e}")
            import traceback
            self.logger.error(traceback.format_exc())
            return None, []

    def _extract_lipsync_data(self, audio_file: str) -> List[LipSyncData]:
        """
        从音频文件提取口型同步数据
        
        Args:
            audio_file: 音频文件路径
            
        Returns:
            口型同步数据列表
        """
        try:
            # 打开WAV文件
            with wave.open(audio_file, 'rb') as wav_file:
                # 获取音频参数
                sample_rate = wav_file.getframerate()
                n_frames = wav_file.getnframes()
                audio_data = wav_file.readframes(n_frames)

                # 转换为numpy数组
                audio_array = np.frombuffer(audio_data, dtype=np.int16)

                # 计算每帧的时间间隔(60 FPS)
                fps = 60
                frame_interval = 1.0 / fps
                samples_per_frame = int(sample_rate * frame_interval)

                lipsync_data = []

                # 按帧分析音频
                for i in range(0, len(audio_array), samples_per_frame):
                    frame_data = audio_array[i:i + samples_per_frame]

                    if len(frame_data) == 0:
                        break

                    # 计算RMS音量
                    rms = np.sqrt(np.mean(frame_data.astype(np.float32) ** 2))
                    max_amplitude = 32768.0  # 16-bit音频最大值
                    volume = min(rms / max_amplitude, 1.0)

                    # 将音量映射到嘴巴张开度(0-1)
                    # Fish Audio音质更好,可以使用更敏感的映射
                    mouth_open = min(volume * 3.0, 1.0)

                    # 添加口型数据
                    timestamp = i / sample_rate
                    lipsync_data.append(
                        LipSyncData(
                            timestamp=timestamp,
                            volume=volume,
                            mouth_open=mouth_open
                        )
                    )

                self.logger.debug(f"提取了 {len(lipsync_data)} 帧口型数据")
                return lipsync_data

        except Exception as e:
            self.logger.error(f"提取口型数据失败: {e}")
            return []

    def test_connection(self) -> bool:
        """
        测试API连接
        
        Returns:
            连接是否成功
        """
        try:
            self.logger.info("正在测试Fish Audio API连接...")
            
            # 使用简短文本测试
            audio, lipsync_data = self.synthesize("测试")
            
            if audio is not None:
                self.logger.info("✓ Fish Audio API连接测试成功!")
                return True
            else:
                self.logger.error("✗ Fish Audio API连接测试失败")
                return False
                
        except Exception as e:
            self.logger.error(f"Fish Audio API连接测试异常: {e}")
            return False

    def get_audio_duration(self, audio: Optional[AudioSegment] = None) -> float:
        """
        获取音频时长(秒)
        
        Args:
            audio: 音频对象
            
        Returns:
            音频时长(秒)
        """
        if audio is None:
            audio = self.current_audio

        if audio is None:
            return 0.0

        return len(audio) / 1000.0
